; ==============================================================================
; Apple II [$D0 ROM] (341-0016) - Programmer's Aid #1 [1978]
; ------------------------------------------------------------------------------
; Part 4 [$D52E~$D5BB]: Tape Verify Routine by Steve Wozniak [WOZ], 1978-01;
; Copyright (c) 1978 by Apple Computer Inc. All Rights Reserved
; ------------------------------------------------------------------------------
; Instructions are in the Programmer's Aid #1 Installation and Operating Manual
; ==============================================================================
; Analyzed (via McFadden's SourceGen) by James Davis [Last Updated: 2020-07-10]
; ==============================================================================
;
; ==============================================================================
; Tape Verify Routine 6502 Equates:
; ==============================================================================
;
CHKSUM EQU $2E {addr/1} ;Tape Input Accumulated Checksum
A1 EQU $3C {addr/2} ;Monitor General Purpose A1-Register
HIMEM EQU $4C {addr/2} ;BASIC HIMEM Address Pointer
PP EQU $CA {addr/2} ;BASIC Start of Program Pointer
PRLEN EQU $CE {addr/2} ;BASIC Program Length
XSAVE EQU $D8 {addr/1} ;BASIC X-Index Register Safe
USRADR EQU $03F8 {addr/3} ;Monitor User Command (Ctrl-Y) Vector
HDRSET EQU $F11E ;BASIC Set Tape Pointers to $CE,$CF
PRGSET EQU $F12C ;BASIC Set Tape Pointers for Program
NXTA1 EQU $FCBA ;Monitor Routine to INC (A1) then CMP (A2)
HEADR EQU $FCC9 ;Monitor Write Tape Sync Header Routine
RDBYTE EQU $FCEC ;Monitor Tape READ Routine (1-Byte|8-Bits)
RD2BIT EQU $FCFA ;Monitor Tape READ Routine (2 Transitions)
RDBIT EQU $FCFD ;Monitor Tape READ Routine (1 Transition)
PRA1 EQU $FD92 ;Print CR, Hex of (A1), then Minus Sign
PRBYTE EQU $FDDA ;Print A-Reg as Two-Digit Hex Number
COUT EQU $FDED ;Print A-Reg to Output Device
FINISH EQU $FF26 ;Check Accumulated Checksum & Ring Bell
PRERR EQU $FF2D ;Print "ERR" & Sound Bell (Beep)
ORG $D52E
;
; ==============================================================================
; Tape Verify Routines:
; ==============================================================================
; Set Monitor User Command (Ctrl-Y) Vector to Tape Verify Routine Location:
; ------------------------------------------------------------------------------
;
; ----------------------------------- ;Monitor Verify S/R Entry Pt.: D52EG <Rtn>
; ;(to verify Mem-Range just saved on Tape)
;
; ----------------------------------- ;Setup Mon User Cmd (Ctrl-Y) Location:
D52E: A9 54 SETTVCYV LDA #<TAPEVFY ;Get Tape Verify Routine Address, Low
D530: A0 D5 LDY #>TAPEVFY ;Get Tape Verify Routine Address, High
D532: 4C B0 D5 JMP SETUSRADR ;Setup Mon User Cmd (Ctrl-Y) Vector
; ==============================================================================
; Tape Verify BASIC Routine:
; ==============================================================================
;
; ----------------------------------- ;BASIC Verify S/R Entry Pt.: Call -10955
; ;(to verify a program just saved on Tape)
D535: 86 D8 VFYBSC STX XSAVE ;Preserve X-Index Register for BASIC
; ;Calculate Program Length, Put into PRLEN:
D537: 38 SEC ;Prep for Subtract w/o Borrow [A-Data-!C]
D538: A2 FF LDX #$FF ;Prep X-Index: Adrs+1, X=255=-1 & X=256=0
D53A: B5 4D GETLEN LDA HIMEM+1,X ;GET HIMEM Address, Low 1st & High 2nd It
D53C: F5 CB SBC PP+1,X ;Subtract Program Start Address, Low/High
D53E: 95 CF STA PRLEN+1,X ;Set Program Length, Low 1st & High 2nd
D540: E8 INX ;Advance X-Index: X=255=-1 -> X=256=0
D541: F0 F7 BEQ GETLEN ;Loop to Do High Addresses, 2nd Iteration
D543: 20 1E F1 JSR HDRSET ;Set Tape Pointers to ...
D546: 20 54 D5 JSR TAPEVFY ;Verify Header on Tape
D549: A2 01 LDX #1 ;Prep for PRGSET
D54B: 20 2C F1 JSR PRGSET ;Set Tape Pointers to ...
D54E: 20 54 D5 JSR TAPEVFY ;Verify Program on Tape
D551: A6 D8 LDX XSAVE ;Restore X-Reg for BASIC
D553: 60 RTS ;Return to Caller
; ==============================================================================
; Tape Verify RAM Image (A1,A2):
; ==============================================================================
;
D554: 20 FA FC TAPEVFY JSR RD2BIT ;Monitor Tape READ Routine (2 Transitions)
D557: A9 16 LDA #$16 ;Set Synchronization Header Length
D559: 20 C9 FC JSR HEADR ;Synchronize on Tape Header
D55C: 85 2E STA CHKSUM ;Initialize Tape Accumulated Checksum
D55E: 20 FA FC JSR RD2BIT ;Monitor Tape READ Routine (2 Transitions)
; ----------------------------------- ;Read a Bit from Tape (Loop):
D561: A0 24 VRFY2 LDY #$24 ;Set Count for RD2BIT/RDBIT Sampling
; ;^[Gets Reduced Until Voltage Transitions]
; ;^[(Used to Set Carry Flag for a One-Bit)]
D563: 20 FD FC JSR RDBIT ;Monitor Tape READ Routine (1 Transition)
D566: B0 F9 BCS VRFY2 ;Loop if RD2BIT/RDBIT Read a One-Bit
D568: 20 FD FC JSR RDBIT ;Monitor Tape READ Routine (1 Transition)
D56B: A0 3B LDY #$3B ;Set Count for RD2BIT/RDBIT Sampling
; ;^[Gets Reduced Until Voltage Transitions]
; ;^[2 Transitions/Bit; 16 Transitions/Byte]
; ----------------------------------- ;Read a Byte from Tape (Loop):
D56D: 20 EC FC VRFY3 JSR RDBYTE ;Monitor Tape READ Routine (1-Byte|8-Bits)
D570: F0 0E BEQ EXTDEL ;RDBYTE Returns (X=0)->(Z=1); Always Taken
;
; ----------------------------------- ;Accumulator contains Byte Read from Tape
D572: 45 2E VFYLOOP EOR CHKSUM ;Update Tape Accumulated Checksum
D574: 85 2E STA CHKSUM ;Set New Tape Accumulated Checksum
D576: 20 BA FC JSR NXTA1 ;Increment A1; Sets Carry Flag if A1>A2
D579: A0 34 LDY #$34 ;Set Count for RD2BIT/RDBIT Sampling
; ;^[Gets Reduced Until Voltage Transitions]
; ;^[2 Transitions/Bit; 16 Transitions/Byte]
; ;^[One < used in Read for an Extra 12 (?)]
D57B: 90 F0 BCC VRFY3 ;Loop Until A1>A2
D57D: 4C 26 FF JMP FINISH ;Verify Checksum & Beep; Returns to Caller
; ----------------------------------- ;Extra Delay to Equalize Timing:
D580: EA EXTDEL NOP ;Delay 2 Machine Cycles
D581: EA NOP ;Delay 2 Machine Cycles More
D582: EA NOP ;Delay 2 Machine Cycles (+12 usec total)
; ----------------------------------- ;Accumulator contains Byte Read from Tape
D583: C1 3C CMP (A1,X) ;Is Byte in Mem Same as Byte from Tape?
D585: F0 EB BEQ VFYLOOP ;Loop if Bytes Match
; =================================== ;Else, Handle Error:
D587: 48 PHA ;Push/Save Wrong Byte from Tape
D588: 20 2D FF JSR PRERR ;Print "ERR" & Sound Bell (Beep)
D58B: 20 92 FD JSR PRA1 ;Print CR, (A1:Address), then Minus Sign
D58E: B1 3C LDA (A1),Y ;Get Byte from Memory at (A1:Address),Y=0
D590: 20 DA FD JSR PRBYTE ;Print A-Reg as Two-Digit Hex Number
D593: A9 A0 LDA #' ' | $80 ;Get a Blank/Space Character
D595: 20 ED FD JSR COUT ;Print A-Reg to Output Device
D598: A9 A8 LDA #'(' | $80 ;Get an Open-Parenthesis Character
D59A: 20 ED FD JSR COUT ;Print A-Reg to Output Device
D59D: 68 PLA ;Pull/Retrieve Bad Byte Saved from Tape
D59E: 20 DA FD JSR PRBYTE ;Print A-Reg as Two-Digit Hex Number
D5A1: A9 A9 LDA #')' | $80 ;Get a Close-Parenthesis Character
D5A3: 20 ED FD JSR COUT ;Print A-Reg to Output Device
D5A6: A9 8D LDA #$8D ;Get High ASCII Ctrl-M: Carriage Return
D5A8: 4C ED FD JMP COUT ;Print A-Reg to Output; Returns to Caller
; =================================== ;Extra Repeated Code (Unused/Filler):
D5AB: A9 8D XCROUT LDA #$8D ;Get High ASCII Ctrl-M: Carriage Return
D5AD: 4C ED FD JMP COUT ;Print A-Reg to Output; Returns to Caller
; ==============================================================================
; Monitor User Command (Ctrl-Y) Vector Setup Routine:
; ==============================================================================
; Shared by: Tape Verify, Relocater, & RAM Test Routines
; ------------------------------------------------------------------------------
;
; ----------------------------------- ;Setup Mon User Cmd (Ctrl-Y) Vector:
D5B0: 8D F9 03 SETUSRADR STA USRADR+1 ;Preset User Address, Low
D5B3: 8C FA 03 STY USRADR+2 ;Preset User Address, High
D5B6: A9 4C LDA #$4C ;Get JMP OpCode
D5B8: 8D F8 03 STA USRADR ;Preset to JMP OpCode
D5BB: 60 RTS ;Return to Caller